﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

using mvcForum.Core;
using mvcForum.Core.Abstractions.Interfaces;
using mvcForum.Core.Specifications;
using mvcForum.Web.Controllers;
using mvcForum.Web.Extensions;
using mvcForum.Web.ViewModels;
using mvcForum.Web.ViewModels.Create;
using mvcForum.Web.Areas.ForumAdmin.Helpers;
using mvcForum.Web.Interfaces;
using mvcForum.Core.Interfaces.Data;

namespace mvcForum.Web.Areas.ForumAdmin.Controllers {

	public class UserController : ForumAdminBaseController {
		private readonly IRepository<ForumUser> userRepo;
		private readonly IRepository<Group> groupRepo;
		private readonly IRepository<GroupMember> gmRepo;
		private readonly IRepository<BannedIP> bipRepo;

		public UserController(IWebUserProvider userProvider, IContext context)
			: base(userProvider, context) {

			this.userRepo = this.GetRepository<ForumUser>();
			this.groupRepo = this.GetRepository<Group>();
			this.gmRepo = this.GetRepository<GroupMember>();
			this.bipRepo = this.GetRepository<BannedIP>();
		}

		#region Create
		public ActionResult Create() {
			var model = new CreateForumUserViewModel();
			return View(model);
		}

		[HttpPost]
		public ActionResult Create(CreateForumUserViewModel model) {
			//if (ModelState.IsValid) {
			//    // TODO: Use membership provider!
			//    ForumUser user = new ForumUser(model.Name, model.Email);
			//    user.SetPassword(model.Password);
			//    //var user = this.userRepository.Create(model.Name, model.Email, model.Password);
			//    this.userRepository.Create(user);
			//    if (model.SendActivationEmail) {
			//        // TODO:
			//    }
			//    else if (model.Active) {
			//        user.Activate(user.GetActivationCode());
			//    }

			//    this.userRepository.Commit();
			//    return RedirectToAction("Index");
			//}
			return View(model);
		}
		#endregion

		//#region Read/Update
		public ActionResult Index() {
			return View();
		}

		public ActionResult Update(Int32 id) {
			// TODO: Access!
			ForumUser user = this.GetRepository<ForumUser>().Read(id);

			return View(new mvcForum.Web.Areas.ForumAdmin.ViewModels.ForumUser { Id = user.Id, Path = BreadcrumbHelper.BuildPath(user, Url) });
		}

		[NonAction]
		private void PopulateForumUserViewModel(ForumUserViewModel model, IEnumerable<Group> groups, IEnumerable<Group> memberOf) {
			// Create the group view models.
			List<GroupViewModel> groupVMs = new List<GroupViewModel>();
			foreach (var group in groups) {
				groupVMs.Add(new GroupViewModel(group));
			}
			// Let's order them by name.
			model.Groups = groupVMs.OrderBy(x => x.Name);

			// Create the list of groups the user is member of.
			List<GroupViewModel> meberOfVMs = new List<GroupViewModel>();
			foreach (var group in memberOf) {
				meberOfVMs.Add(new GroupViewModel(group));
			}
			model.MemberOf = meberOfVMs;
		}

		/// <summary>
		/// Method for updating the user's data.
		/// </summary>
		/// <param name="model">The user view model.</param>
		/// <returns></returns>
		[HttpPost]
		public ActionResult Edit(ForumUserViewModel model) {
			ForumUser user = this.userRepo.Read(model.Id);
			if (ModelState.IsValid) {

			}

			model.Name = user.Name;
			model.FirstVisit = user.FirstVisit;
			//model.FirstVisit = user.Created;
			model.LastVisit = user.LastVisit;
			model.LastIP = user.LastIP;

			// Get all groups.
			var groups = this.groupRepo.ReadAll();

			// Get the groups the user is member of.
			//var memberOf = this.elementRepository.ReadGroups(user);

			this.PopulateForumUserViewModel(model, groups, user.Groups());

			return View(model);
		}
		//#endregion

		/// <summary>
		/// Method for removing a given user from a given group.
		/// </summary>
		/// <param name="id">The user's id.</param>
		/// <param name="groupId">The group's id.</param>
		/// <param name="confirm">True to confirm the removal of the user from the group otherwise false.</param>
		/// <returns></returns>
		[HttpPost]
		public ActionResult RemoveMember(Int32 id, Int32 groupId, Boolean confirm) {
			// Should any action be taken?
			if (confirm) {
				// Get the user.
				var user = this.userRepo.Read(id);
				// Get the groups the user is member of.
				var memberOf = gmRepo.ReadMany(new GroupMemberSpecifications.SpecificUser(user));

				// Let's iterate them.
				foreach (var member in memberOf) {
					// Is this the group member relationship we're looking for?
					if (member.Group.Id == groupId && member.ForumUser.Id == id) {
						// It is, let's delete it!
						this.gmRepo.Delete(member);
						// Done, the user can only have one group membership with the same group, so we're done!
						break;
					}
				}
				this.Context.SaveChanges();
			}

			return View();
		}

		/// <summary>
		/// Method for adding a given user to a given group.
		/// </summary>
		/// <param name="id">The user's id.</param>
		/// <param name="groupId">The group's id.</param>
		/// <returns></returns>
		[HttpPost]
		public ActionResult AddMember(Int32 id, Int32 groupId) {
			// Get the user.
			ForumUser user = this.userRepo.Read(id);
			// Get the group.
			Group group = this.groupRepo.Read(groupId);

			// Is the user already a member of this group?
			if (!this.gmRepo.ReadMany(new GroupMemberSpecifications.SpecificUserAndGroup(user, group)).Any()) {
				// No, let's add him then.
				this.gmRepo.Create(new GroupMember(group, user));
				this.Context.SaveChanges();
			}

			return RedirectToAction("Edit", new { id = user.Id });
		}

		#region Delete
		public ActionResult Delete(int id) {
			// TODO: Access!!
			var model = new ForumUserViewModel(this.userRepo.Read(id));
			return View(model);
		}

		[HttpPost]
		public ActionResult Delete(Int32 id, Boolean confirm) {
			// TODO: Access!!
			var user = this.userRepo.Read(id);
			if (ModelState.IsValid && confirm) {
				this.userRepo.Delete(user);
				this.Context.SaveChanges();

				return RedirectToAction("Index");
			}
			var model = new ForumUserViewModel(user);
			return View(model);
		}
		#endregion

		public ActionResult BanIP(Int32 userId, String ip) {
			var banned = this.bipRepo.ReadOne(new BannedIPSpecifications.SpecificIP(ip));
			if (banned == null) {
				BannedIP bip = new BannedIP(ip);
				this.bipRepo.Create(bip);
				this.Context.SaveChanges();
			}

			return RedirectToAction("Edit", new { id = userId });
		}
	}
}